package org.cardcopier.file;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class AbstractFileLocation implements FileLocation {

	private final File directory;
	private final FileFilter fileFilter;
	private final Map<String, File> fileCache = new HashMap<String, File>();

	public AbstractFileLocation(File directory, FileFilter fileFilter) {
		this.directory = directory;
		this.fileFilter = fileFilter;
		refresh();
	}

	public void refresh() {
		fileCache.clear();
		List<File> files = deepListFiles(directory, fileFilter);
		for (File file : files) {
			putFileInCache(fileCache, file);
		}
	}

	protected abstract void putFileInCache(Map<String, File> fileCache, File file);
	protected abstract File getFileFromCache(Map<String, File> fileCache, String key);
	
	private List<File> deepListFiles(File rootDir, FileFilter fileFilter) {
		List<File> matchingFiles = new ArrayList<File>();
		deepListFiles(matchingFiles, rootDir, fileFilter);
		return matchingFiles;
	}

	private void deepListFiles(List<File> matchingFiles, File dir, FileFilter fileFilter) {
		addFileArrayToList(matchingFiles, dir.listFiles(fileFilter));
		File[] files = dir.listFiles();
		if (files != null) {
			for (File potentialSubDir : files) {
				if (potentialSubDir.isDirectory()) {
					deepListFiles(matchingFiles, potentialSubDir, fileFilter);
				}
			}
		}
	}

	private void addFileArrayToList(List<File> fileList, File[] fileArray) {
		if (fileArray != null) {
			for (File file : fileArray) {
				fileList.add(file);
			}
		}
	}

	public List<File> getFiles() {
		return new ArrayList<File>(fileCache.values());
	}

	public boolean containsFile(File file) {
		return getFileFromCache(fileCache, file.getName()) != null;
	}
         
    public File getDirectory() {
        return directory;
    }

    public Date getEarliestFileDate() {
        List<File> files = getFiles();
        Date earliestFileDate = null;
        if (files != null && files.size() > 0) {
            Collections.sort(files, new Comparator<File>() {
                public int compare(File f1, File f2) {
                    long diff = f1.lastModified() - f2.lastModified();
                    if (diff != 0) {
                        return diff < 0 ? -1 : 1;
                    } else {
                        return 0;
                    }
                }
            });
            earliestFileDate = new Date(files.get(0).lastModified());
        }
        return earliestFileDate;
    }
 
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(this instanceof AbstractFileLocation)) {
            return false;
        }
        AbstractFileLocation a = (AbstractFileLocation)o;
        if (!directory.equals(a.directory)) return false;
        if (!fileFilter.equals(a.fileFilter)) return false;
        return true;
    }
}